package com.ionehe.group.common.uaa.ex.domain.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.base.Throwables;
import com.google.common.collect.Lists;
import com.ionehe.group.common.io.Response;
import com.ionehe.group.common.uaa.ex.application.converter.CustomerConverter;
import com.ionehe.group.common.uaa.ex.domain.service.UserReadService;
import com.ionehe.group.common.uaa.ex.enums.TerminalType;
import com.ionehe.group.common.uaa.ex.enums.UserType;
import com.ionehe.group.common.uaa.ex.exception.BusinessException;
import com.ionehe.group.common.uaa.ex.model.*;
import com.ionehe.group.common.uaa.ex.dto.CustomerInfoDTO;
import com.ionehe.group.common.uaa.ex.dto.FunctionDTO;
import com.ionehe.group.common.uaa.ex.enums.ErrorMessages;
import com.ionehe.group.common.uaa.ex.enums.FunctionStatus;
import com.ionehe.group.common.uaa.ex.enums.SetMealEnum;
import com.ionehe.group.common.uaa.ex.enums.UserStatus;
import com.ionehe.group.common.uaa.ex.dao.*;
import com.ionehe.group.common.uaa.ex.domain.service.CustomerWriteService;
import com.ionehe.group.common.uaa.ex.domain.service.FunctionReadService;
import com.ionehe.group.common.uaa.ex.domain.service.UserCacheWriteService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * Copyright (c) 2020 ionehe.com
 * Date: 2020/11/26 0026
 * Time: 15:02
 *
 * @author 2020年 <a href="mailto:a@ionehe.com">秀</a>
 */
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class CustomerWriteServiceImpl implements CustomerWriteService {
    @Resource
    CustomerInfoDao customerInfoDao;
    @Resource
    SetMealDao setMealDao;
    @Resource
    CustomerFunctionDao customerFunctionDao;
    @Resource
    CustomerSetMealDao customerSetMealDao;
    @Resource
    SetMealFunctionDao setMealFunctionDao;
    @Resource
    UserRoleDao userRoleDao;
    @Resource
    UserInfoDao userInfoDao;
    @Resource
    LoginInfoDao loginInfoDao;
    @Resource
    RoleInfoDao roleInfoDao;
    @Resource
    RoleFunctionDao roleFunctionDao;
    @Autowired
    UserCacheWriteService userCacheWriteService;
    @Autowired
    FunctionReadService functionReadService;
    @Autowired
    CustomerConverter customerConverter;
    @Autowired
    UserReadService userReadService;

    @Override
    public Response customerAddAndUpdate(CustomerInfoDTO customerInfoDTO) {
        if (customerInfoDTO == null) return Response.no(ErrorMessages.ILLEGAL_PARAMS.toString());

        log.info("CustomerReadeServiceImpl[]customerAddAndUpdate[]start! customerInfoDTO:{}", customerInfoDTO);
        // 根据套餐id查询套餐信息
        if (customerInfoDTO.getId() == null) {
            UaaSetMeal setMeal = setMealDao.selectByMealId(customerInfoDTO.getSetMealId());
            log.info("CustomerReadeServiceImpl[]selectByMealId[]success!");

            if (setMeal == null) return Response.no("套餐不存在");
            List<UaaCustomerInfo> customerInfos = customerInfoDao.selectCustomerls();
            // 校验企业名称重复
            if (checkCustomerName(customerInfos, customerInfoDTO.getName())) return Response.no("该名称已存在");
            // 校验企业电话重复
            if (checkCustomerPhone(customerInfos, customerInfoDTO.getAccount())) return Response.no("该账户已存在");

            // 更新企业表
            Date creatTime = new Date();
            UaaCustomerInfo customerInfo = new UaaCustomerInfo();
            BeanUtil.copyProperties(customerInfoDTO, customerInfo);
            customerInfo.setCreateTime(creatTime);
            customerInfoDao.insertSelective(customerInfo);
            // 更新用户
            UaaUserInfo userInfo = new UaaUserInfo();
            userInfo.setCustomerId(customerInfo.getId());
            userInfo.setName(customerInfoDTO.getName());
            userInfo.setPhone(customerInfoDTO.getAccount());
            userInfo.setCreateTime(creatTime);
            userInfo.setAvatar("https://rd-demo.oss-cn-hangzhou.aliyuncs.com/01112012ajf.JPG");
            userInfo.setStatus(UserStatus.USING.getValue());
            Integer terminal = customerInfoDTO.getTerminal();
            userInfo.setTerminal(terminal == null ? TerminalType.PC.getValue() : terminal);
            userInfo.setType(UserType.ADMIN.getValue());
            userInfoDao.insertSelective(userInfo);
            // 添加登录表
            UaaLoginInfo loginInfo = new UaaLoginInfo();
            loginInfo.setCreateTime(creatTime);
            loginInfo.setAccount(customerInfoDTO.getAccount());
            BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
            String password = customerInfoDTO.getPassword();
            password = StrUtil.isNotBlank(password) ? password : customerInfoDTO.getAccount() + "@hello";
            loginInfo.setPassword(bCryptPasswordEncoder.encode(password));
            loginInfo.setUserId(userInfo.getId());
            loginInfo.setAlreadyFirstLogin(false);
            loginInfo.setIsDelete(false);
            loginInfoDao.insert(loginInfo);
            // 更新企业套餐关系表
            UaaCustomerSetMeal customerSetMeal = new UaaCustomerSetMeal();
            customerSetMeal.setCreateTime(creatTime);
            customerSetMeal.setSetMealId(customerInfoDTO.getSetMealId());
            String predictTime = setMeal.getDuration();
            // 计算超时时间
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(creatTime);
            calendar.add(Calendar.MONTH, SetMealEnum.getKey(predictTime));
            Date timeOut = calendar.getTime();
            customerSetMeal.setTimeout(timeOut);
            customerSetMeal.setCustomerId(customerInfo.getId());
            customerSetMeal.setStatus(1);
            customerSetMealDao.insert(customerSetMeal);
            log.info("CustomerReadeServiceImpl[]customerSetMealInsert[]success!");

            // 查询套餐关联的权限集合
            List<Long> functionList = setMealFunctionDao.selectFunctionIdsBysetMealId(setMeal.getId());
            Response<List<FunctionDTO>> funRes = functionReadService.selectByIdList(functionList);
            if (!funRes.success()) {
                return Response.no(funRes.getMessage());
            }
            List<FunctionDTO> functionDTOList = funRes.getData();

            functionList = functionDTOList.stream()
                    .filter(f -> Objects.equals(f.getStatus(), FunctionStatus.ON_SHELF.getValue()))
                    .map(FunctionDTO::getId)
                    .map(Long::valueOf)
                    .collect(Collectors.toList());

            // 新增企业与权限表
            List<UaaCustomerFunction> customerFunctions = new ArrayList<>();
            for (Long funId : functionList) {
                UaaCustomerFunction customerFunction = new UaaCustomerFunction();
                customerFunction.setCreateTime(creatTime);
                customerFunction.setCustomerId(customerInfo.getId());
                customerFunction.setFunctionId(funId);
                customerFunctions.add(customerFunction);
            }
            if (CollUtil.isNotEmpty(customerFunctions)) {
                // TODO 硬编码，待优化
                UaaCustomerFunction userManagerFun = new UaaCustomerFunction();
                userManagerFun.setFunctionId(4L);
                userManagerFun.setCustomerId(customerInfo.getId());
                userManagerFun.setCreateTime(new Date());
                UaaCustomerFunction roleManagerFun = new UaaCustomerFunction();
                roleManagerFun.setFunctionId(5L);
                roleManagerFun.setCreateTime(new Date());
                roleManagerFun.setCustomerId(customerInfo.getId());

                customerFunctions.add(userManagerFun);
                customerFunctions.add(roleManagerFun);
                customerFunctionDao.insertList(customerFunctions);
            }
            log.info("CustomerReadeServiceImpl[]customerFunctionInsert[]success!");

            return Response.yes("添加公司成功");
        } else {
            Date creatDate = new Date();
            // 判断企业信息是否存在
            UaaCustomerInfo customerInfo = customerInfoDao.selectByPrimaryKey(customerInfoDTO.getId());
            log.info("CustomerReadeServiceImpl[]customerInfoSelect[]success!");
            if (Objects.isNull(customerInfo)) {
                return Response.no("信息已不存在");
            }
            List<UaaCustomerInfo> customerInfos = customerInfoDao.selectCustomerls();
            // 判断企业名称和号码是否改变
            if (!customerInfoDTO.getName().equals(customerInfo.getName())) {
                // 校验企业名称重复
                if (checkCustomerName(customerInfos, customerInfoDTO.getName())) {
                    return Response.no("该名称已存在");
                }
            }
            String oldAccount = customerInfo.getAccount();
            if (!customerInfoDTO.getAccount().equals(customerInfo.getAccount())) {
                // 校验企业电话重复
                if (checkCustomerPhone(customerInfos, customerInfoDTO.getAccount())) {
                    return Response.no("该账户已存在");
                }
            }

            // 更新公司信息
            UaaCustomerInfo customer = customerConverter.dto2do(customerInfoDTO);
            customer.setUpdateTime(new Date());
            customerInfoDao.updateByPrimaryKeySelective(customer);
            Example e = new Example(UaaUserInfo.class);
            e.createCriteria()
                    .andEqualTo("isDelete", false)
                    .andEqualTo("phone", oldAccount);
            // 更新用户信息
            UaaUserInfo user = new UaaUserInfo();
            user.setName(customerInfoDTO.getName());
            user.setPhone(customerInfoDTO.getAccount());
            userInfoDao.updateByExampleSelective(user, e);
            // 更新登陆信息
            UaaLoginInfo loginInfo = new UaaLoginInfo();
            loginInfo.setUpdateTime(new Date());
            loginInfo.setAccount(customerInfoDTO.getAccount());
            BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
            String password = customerInfoDTO.getPassword();
            password = StrUtil.isNotBlank(password) ? password : customerInfoDTO.getAccount() + "@hello";
            loginInfo.setPassword(bCryptPasswordEncoder.encode(password));
            Example exa = new Example(UaaLoginInfo.class);
            exa.createCriteria()
                    .andEqualTo("isDelete", false)
                    .andEqualTo("account", oldAccount);
            loginInfoDao.updateByExampleSelective(loginInfo, exa);

            // 判断套餐信息是否修改
            List<Long> setMealIds = customerSetMealDao.selectById(customerInfoDTO.getId());

            if (checkSetMealId(setMealIds, customerInfoDTO.getSetMealId())) {
                // 查询套餐关联的权限集合

                List<Long> functionList = setMealFunctionDao.selectFunctionIdsBysetMealId(customerInfoDTO.getSetMealId());
                // 公司套餐更换，原有角色权限清空
                List<Long> ids = roleInfoDao.selectIdsByCustomerId(customerInfoDTO.getId());
                ArrayList<Long> newFunctionIds = new ArrayList<>();
                if (CollUtil.isNotEmpty(ids)) {
                    Example example = new Example(UaaRoleFunction.class);
                    example.createCriteria().andIn("roleId", ids);
                    List<UaaRoleFunction> roleFunctions = roleFunctionDao.selectByExample(example);
                    if (CollUtil.isNotEmpty(roleFunctions)) {
                        for (UaaRoleFunction roleFunction : roleFunctions) {
                            newFunctionIds.add(roleFunction.getFunctionId());
                        }
                    }
                    newFunctionIds.removeAll(functionList);
                    if (CollUtil.isNotEmpty(newFunctionIds)) {
                        Example example1 = new Example(UaaRoleFunction.class);
                        example1.createCriteria().andIn("roleId", ids)
                                .andIn("functionId", newFunctionIds);

                        roleFunctionDao.deleteByExample(example1);
                    }
                }


                // 更新原有的套餐与企业关系为失效
                customerSetMealDao.updateStatu(customerInfoDTO.getId());
                // 删除之前公司与功能的关系
                customerFunctionDao.deleteByCustomerId(customerInfoDTO.getId());
                UaaSetMeal setMeal = setMealDao.selectByMealId(customerInfoDTO.getSetMealId());
                log.info("CustomerReadeServiceImpl[]selectByMealId[]success!");
                if (!(Objects.isNull(setMeal))) {
                    // 更新企业套餐关系表
                    UaaCustomerSetMeal customerSetMeal = new UaaCustomerSetMeal();
                    customerSetMeal.setCreateTime(creatDate);
                    customerSetMeal.setSetMealId(customerInfoDTO.getSetMealId());
                    String predictTime = setMeal.getDuration();
                    Date startTime = setMeal.getCreateTime();
                    // 计算超时时间
                    Calendar calendar = Calendar.getInstance();
                    if (startTime != null) {
                        calendar.setTime(startTime);
                    }
                    calendar.add(Calendar.MONTH, SetMealEnum.getKey(predictTime));
                    Date timeOut = calendar.getTime();
                    customerSetMeal.setTimeout(timeOut);
                    customerSetMeal.setCustomerId(customerInfo.getId());
                    customerSetMeal.setStatus(1);
                    customerSetMealDao.insert(customerSetMeal);
                    log.info("CustomerReadeServiceImpl[]customerSetMealInsert[]success!");

                    // 新增企业与权限表
                    ArrayList<UaaCustomerFunction> customerFunctions = new ArrayList<>();
                    for (Long aLong : functionList) {
                        UaaCustomerFunction customerFunction = new UaaCustomerFunction();
                        customerFunction.setCreateTime(creatDate);
                        customerFunction.setCustomerId(customerInfo.getId());
                        customerFunction.setFunctionId(aLong);
                        customerFunctions.add(customerFunction);
                    }
                    if (CollUtil.isNotEmpty(customerFunctions)) {
                        // TODO 硬编码，待优化
                        UaaCustomerFunction userManagerFun = new UaaCustomerFunction();
                        userManagerFun.setFunctionId(4L);
                        userManagerFun.setCustomerId(customerInfo.getId());
                        userManagerFun.setCreateTime(new Date());
                        UaaCustomerFunction roleManagerFun = new UaaCustomerFunction();
                        roleManagerFun.setFunctionId(5L);
                        roleManagerFun.setCreateTime(new Date());
                        roleManagerFun.setCustomerId(customerInfo.getId());

                        customerFunctions.add(userManagerFun);
                        customerFunctions.add(roleManagerFun);
                        customerFunctionDao.insertList(customerFunctions);
                    }
                }
            }
            // 清除缓存
            if (customerInfoDTO.getAccount() != null && customerInfoDTO.getPassword() != null) {
                String terminalAccount = TerminalType.PC.getValue() + "_" + customerInfoDTO.getAccount();
                userCacheWriteService.delUser(terminalAccount);
                userCacheWriteService.delUserToken(Lists.newArrayList(terminalAccount));
            }

            return Response.yes("公司编辑成功");
        }
    }

    public Response<Boolean> updateCustomer(CustomerInfoDTO customerInfoDTO) {
        try {
            UaaCustomerInfo customerInfo = new UaaCustomerInfo();
            BeanUtil.copyProperties(customerInfoDTO, customerInfo);
            customerInfoDao.updateByPrimaryKeySelective(customerInfo);
        } catch (Exception e) {
            e.printStackTrace();
            return Response.no(false);
        }
        return Response.yes(true);
    }

    @Override
    public Response<Boolean> customerDelete(Long id) {
        try {
            if (id == null) {
                return Response.no("id为空");
            }
            UaaCustomerInfo customerInfo = customerInfoDao.selectById(id);
            if (Objects.isNull(customerInfo)) {
                return Response.no(ErrorMessages.ILLEGAL_PARAMS.toString());
            }

            // 删除企业
            customerInfoDao.deleteById(id);
            // 删除企业与套餐的关系
            customerSetMealDao.deleteByCustomerId(id);
            // 删除企业与功能的关系
            customerFunctionDao.deleteByCustomerId(id);

            // 查询该公司所有的用户id
            List<Long> userIds = userInfoDao.selectByCustomerId(id);
            if (CollUtil.isNotEmpty(userIds)) {
                Example example1 = new Example(UaaUserInfo.class);
                example1.createCriteria().andIn("id", userIds);
                List<UaaUserInfo> userInfos = userInfoDao.selectByExample(example1);
                // 清除缓存
                List<String> accountList = userInfos.stream().map(UaaUserInfo::getPhone).collect(Collectors.toList());
                userCacheWriteService.delResourceList(accountList);
                userCacheWriteService.delUser(accountList);
                userCacheWriteService.delUserToken(accountList);
            }

            // 用户与角色表清除
            if (!CollectionUtils.isEmpty(userIds)) {
                userRoleDao.deleteByUserIds(userIds);
            }
            // 查出所有的角色id
            List<Long> ids = roleInfoDao.selectIdsByCustomerId(id);
            if (CollUtil.isNotEmpty(ids)) {
                Example example = new Example(UaaRoleFunction.class);
                example.createCriteria().andIn("roleId", ids);
                roleFunctionDao.deleteByExample(example);
            }
            // 删除角色表
            roleInfoDao.updateByCustomerId(id);
            // 删除登录表
            // 查询公司用户的登录信息
            if (!CollectionUtils.isEmpty(userIds)) {
                Example example = new Example(UaaLoginInfo.class);
                example.createCriteria().andIn("userId", userIds);
                List<UaaLoginInfo> loginInfos = loginInfoDao.selectByExample(example);
                List<Long> idList = new ArrayList();
                for (UaaLoginInfo loginInfo : loginInfos) {
                    idList.add(loginInfo.getId());
                }
                loginInfoDao.updateById(idList);
            }
            //        删除企业对应的用户信息
            userInfoDao.deleteByCustomerId(id);
            return Response.yes(true);
        } catch (Exception e) {
            log.error("CustomerReadeServiceImpl[]customerDelete[]error! cause:{}", Throwables.getStackTraceAsString(e));
            return Response.no("删除异常");
        }

    }

    @Async
    @Override
    public void updateLastLoginTime(Long id) {
        UaaCustomerInfo customer = new UaaCustomerInfo();
        customer.setId(id);
        customer.setLastLoginTime(new Date());
        try {
           int i = customerInfoDao.updateByPrimaryKeySelective(customer);
            if (i != 1) {
                throw new BusinessException("更新企业最近一次登陆时间异常!");
            }
        } catch (Exception e) {
            log.warn("CustomerWriteService[]updateLastLoginTime[]update the last login time for customer info by id failed! cause:{}",
                    Throwables.getStackTraceAsString(e));
        }

    }

    /**
     * 编辑企业的时候判断套餐是否更换
     *
     * @param setMealIds
     * @param setMealId
     * @return
     */
    private boolean checkSetMealId(List<Long> setMealIds, Long setMealId) {
        for (Long mealId : setMealIds) {
            if (mealId != setMealId) {
                return true;
            }
        }
        return false;
    }

    private boolean checkCustomerPhone(List<UaaCustomerInfo> customerInfos, String account) {
        for (UaaCustomerInfo customerInfo : customerInfos) {
            if (Objects.equals(customerInfo.getAccount(), account)) {
                return true;
            }
        }
        return false;
    }

    private boolean checkCustomerName(List<UaaCustomerInfo> customerInfos, String name) {
        for (UaaCustomerInfo customerInfo : customerInfos) {
            if (Objects.equals(customerInfo.getName(), name)) {
                return true;
            }
        }
        return false;
    }


    public static void main(String[] args) {
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String encode = bCryptPasswordEncoder.encode("platform" + "@admin.com");
        System.out.println(encode);
        String encode1 = bCryptPasswordEncoder.encode("dev" + "@admin.com");
        System.out.println(encode1);
    }

}
